package com.ruoyi.project.system.user.dao;

import com.ruoyi.project.system.user.domain.LdapUser;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.ldap.core.DirContextOperations;
import org.springframework.ldap.core.LdapTemplate;
import org.springframework.ldap.core.support.AbstractContextMapper;
import org.springframework.ldap.core.support.BaseLdapNameAware;
import org.springframework.ldap.filter.EqualsFilter;
import org.springframework.ldap.support.LdapNameBuilder;
import org.springframework.ldap.support.LdapUtils;
import org.springframework.stereotype.Component;

import javax.naming.Name;
import javax.naming.directory.*;
import javax.naming.ldap.LdapName;
import java.util.List;

@Component
public class LdapUserRepository implements BaseLdapNameAware {

    @Autowired
    private LdapTemplate ldapTemplate;

    private LdapName baseLdapPath;

    @Override
    public void setBaseLdapPath(LdapName baseLdapPath) {
        this.baseLdapPath = baseLdapPath;
    }

    public boolean create(LdapUser ldapUser) {
        Name dn = buildDn(ldapUser);
        ldapTemplate.bind(dn, null, buildAttributes(ldapUser));
        return true;
    }

    public boolean updatePassword(String uid, String newPassword) {
        Name dn = LdapNameBuilder.newInstance(baseLdapPath)
                .add("uid", uid)
                .build();
        LdapUser ldapUser = ldapTemplate.lookup(dn, new LdapUserContextMapper());
        if (ldapUser == null)
            return false;
        final ModificationItem[] passwordChange = new ModificationItem[]{new ModificationItem(
                DirContext.REPLACE_ATTRIBUTE, new BasicAttribute("userPassword",
                newPassword))};
        ldapTemplate.modifyAttributes(dn, passwordChange);
        return true;
    }

    private Name buildDn(LdapUser user) {
        return LdapNameBuilder.newInstance(baseLdapPath)
                .add("uid", user.getUid())
                .build();
    }

    public LdapUser findOne(String uid) {
        Name dn = LdapNameBuilder.newInstance(baseLdapPath)
                .add("uid", uid)
                .build();
        return ldapTemplate.lookup(dn, new LdapUserContextMapper());
    }

    public List<LdapUser> findAll() {
        EqualsFilter filter = new EqualsFilter("objectclass", "inetOrgPerson");
        return ldapTemplate.search(LdapUtils.emptyLdapName(), filter.encode(), new LdapUserContextMapper());
    }

    private Attributes buildAttributes(LdapUser p) {
        Attributes attrs = new BasicAttributes();
        BasicAttribute ocAttr = new BasicAttribute("objectclass");
        ocAttr.add("inetOrgPerson");
        attrs.put(ocAttr);
        attrs.put("uid", p.getUid());
        attrs.put("cn", p.getName());
        attrs.put("sn", p.getLastName());
        attrs.put("mail", p.getEmail());
        attrs.put("userPassword", p.getPassword());
        return attrs;
    }

    private static class LdapUserContextMapper extends AbstractContextMapper<LdapUser> {
        public LdapUser doMapFromContext(DirContextOperations context) {
            LdapUser person = new LdapUser();
            person.setName(context.getStringAttribute("cn"));
            person.setLastName(context.getStringAttribute("sn"));
            person.setUid(context.getStringAttribute("uid"));
            person.setEmail(context.getStringAttribute("mail"));
            return person;
        }
    }
}
